<?php
namespace Monkey\Database\Driver;

use MonkeyException;

/**
 * PDO数据库驱动\Monkey\Database\Driver\PDO
 * @package    Monkey\Database\Driver
 * @author     HuangYi
 * @copyright  Copyright (c) 2011-07-01——2013-03-30
 * @license    New BSD License
 * @version    $Id: \Monkey\Database\Driver\PDO.php 版本号 2013-03-30 $
 */
class PDO implements _Interface
{
    /**
     * @var \PDO
     */
    private $_linker;   //连接
    private $_sql;
    private $_prefix;
    /**
     * @var \PDOStatement
     */
    private $_result;    //
    private $_fetch_model=array(
        'assoc'=>\PDO::FETCH_ASSOC,
        'num'=>\PDO::FETCH_NUM,
        'both'=>\PDO::FETCH_BOTH
    );
    private $_execute_true;
    public function __construct($config,$isTest=false) {
        if(!extension_loaded('pdo') ){
            MonkeyException::halt('没有安装pdo驱动扩展,请先在php.ini中配置安装pdo',1024,__FILE__,__LINE__);
        }
        if(!$isTest){
            $this->_linker= $this->connect($config,false);
        }
    }
    public function connect($config,$isTest=false){
        if ($config['protocol'] == 'sqlite')
            $dsn  = $config['protocol'].':'.($config['file']?$config['file']:$config['host']);
        else if ($config['protocol'] == 'sqlsrv')
            $dsn  = $config['protocol'].':Server='.$config['host'].';Database='.$config['dbname'].';';
        else if ($config['protocol'] == 'mssql' || $config['type'] == 'dblib')
            $dsn  = $config['protocol'].'host='.$config['host'].';dbname='.$config['dbname'].';';
        else {//Mysql，Oracle等
            $dsn  = $config['protocol'].':host='.$config['host'].';dbname='.$config['dbname'].';';
            $dsn .= 'charset='.$config['charset'];
        }
        try {
            $linker = new \PDO($dsn,$config['username'],$config['password'],array(\PDO::ATTR_PERSISTENT=>true));
        } catch (\PDOException $e) {
            if($isTest)return notice(false,array('msg'=>$e->getMessage(),'code'=>$e->getCode()));
            else MonkeyException::halt('连接数据库时出错：'.$e->getMessage(),$e->getCode(),__FILE__,__LINE__);
        }
        if($isTest)return notice(true,array('msg'=>'连接成功','code'=>NULL));
        $config['protocol']=='mysql'
            && $linker->exec('set names '.$config['charset'].';');//mysql需要单独设置字符集
        $this->_prefix=$config['prefix']?$config['prefix']:'';
        if(!is_null($this->_linker))unset($this->clear()->_linker);
        $this->_linker=$linker;
        return true;
    }
    public function escape($data){
        if (is_array($data)) return array_map(array($this,'escape'), $data);
        if (is_null($data)) return 'NULL';
        if (is_bool($data)) return $data ? '1' : '0';
        if (is_int($data)) return (int) $data;
        if (is_float($data)) return (float) $data;
        $data = sql_encode($data);
        return $this->_linker->quote($data);
    }
    public function getPreFix(){
        return $this->_prefix;
    }
    public function transaction($type) {
        if($type===0 or $type=='begin'){
            $this->_linker->beginTransaction();
        }elseif($type===1 or $type=='commit'){
            $this->_linker->commit();
        }elseif($type===-1 or $type=='rollback'){
            $this->_linker->rollBack();
        }
        return $this;
    }
    public function query($sql){
        $this->clear();
        $this->_sql = preg_replace('/\{:(\S+?):\}/',$this->_prefix.'$1',$sql);
        if (preg_match('/^\s*select|show\s*/ie',$sql)){
            $this->_result = $this->_linker->query($sql);
        }  else {
            $this->_result = $this->_linker->exec($sql);
        }
        $this->_execute_true = $this->_result === FALSE ? FALSE:TRUE;
        return $this;
    }
    public function isSuccess(){
        return $this->_execute_true;
    }
    public function resultCount(){
        if(!is_object($this->_result))return null;
        return $this->_result->rowCount();
    }
    public function resultAll($model=FETCH_ASSOC){
        if(!is_object($this->_result))return null;
        return sql_decode($this->_result->fetchAll($this->_fetch_model[$model]));
    }
    public function result($model=FETCH_ASSOC){
        if(!is_object($this->_result))return null;
        return sql_decode($this->_result->fetch($this->_fetch_model[$model]));
    }
    public function affectedRows(){
        return $this->_execute_true ? $this->_result : NULL;
    }
    public function insertId(){
        return $this->_execute_true ? $this->_linker->lastInsertId() : NULL;
    }
    public function lastSql(){
        return $this->_sql;
    }
    public function errorCode(){
        return $this->_linker->errorCode();
    }
    public function errorMessage(){
        return $this->_linker->errorInfo(). '【sql：】' . $this->_sql;
    }
    public function clear(){
        unset($this->_result);
        return $this;
    }
    public function destroy(){
        $this->clear();
        unset($this->_linker);
    }
}